package com.gitee.l0km.codegen.thrift;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import com.google.common.base.Strings;

import com.google.common.base.Joiner;

import com.google.common.base.MoreObjects;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;

import static com.google.common.base.Preconditions.*;

public class CxxHelper {

	public CxxHelper() {
	}
	private static ThreadLocal<ArrayList<String>> tlsPackageName=new ThreadLocal<ArrayList<String>>() ;
	private static ThreadLocal<Boolean> tlsMultiline = new ThreadLocal<Boolean>();
	private static String getCurrent(String separator){
		ArrayList<String> pkg = tlsPackageName.get();
		if(null == pkg){
			return "";
		}
		return Joiner.on(separator).join(pkg);
	}
	public static String getCurrentNamespace(){
		return getCurrent("::");
	}
	public static String getCurrentPackageAsJava(){
		return getCurrent(".");
	}
	public static boolean isCurrentPackage(Class<?> clazz){
		return null == clazz 
				? false
				: clazz.getPackage().getName().equals(getCurrentPackageAsJava());
	}
	/**
	 * @param packageName java package或c++ namespace
	 * @param multiline
	 * @return namespace开始字符串
	 */
	public static String namespaceBegin(String packageName, boolean multiline){		
		packageName = MoreObjects.firstNonNull(packageName, "");
		ArrayList<String> names = Lists.newArrayList(Iterables.filter(Arrays.asList(packageName.split("(\\.|::)")),new Predicate<String>(){
			@Override
			public boolean apply(String input) {
				return !input.trim().isEmpty();
			}}));
		tlsPackageName.set(names);
		tlsMultiline.set(multiline);
		StringBuilder builder=new StringBuilder();
		for(String name:names){
			builder.append(String.format("namespace %s{",name));
			if(multiline){
				builder.append("\n");
			}
		}
		return builder.toString();
	}
	public static String namespaceBegin(Class<?> clazz){
		return null==clazz ? "// class is null\n" : namespaceBegin(clazz.getPackage().getName(), true);
	}
	public static String namespaceBegin(Class<?> clazz,boolean multiline){
		return null==clazz ? "// class is null\n" : namespaceBegin(clazz.getPackage().getName(), multiline);
	}
	public static String namespaceEnd(){
		List<String> names = MoreObjects.firstNonNull(tlsPackageName.get(),Collections.<String>emptyList());	
		StringBuilder builder=new StringBuilder();
		for(String name:Lists.reverse(names)){
			builder.append(String.format("} /* namespace %s */",name));
		}
		if(Boolean.TRUE.equals(tlsMultiline.get())){
			builder.append("\n");
		}
		tlsPackageName.remove();
		tlsMultiline.remove();
		return builder.toString();		
	}
	
	/**
	 * java 包名或类名转为c++ namespace或类名
	 * @param javaName package或类名
	 * @param isfull 为{@code false}返回空串，{@code javaName}为类名时必须为{@code true},否则无法返回正确结果
	 */
	public static String cxxNamespace(String javaName,boolean isfull){
		if(null==javaName || !isfull){
			return "";
		}
		// . $ 都替换为 ::
		return javaName.replaceAll("[\\.\\$]", "::");
	}
	public static String cxxNamespace(Class<?>clazz,boolean isfull ){
		return null==clazz ? "// class is null\n" :  cxxNamespace(clazz.getPackage().getName(),isfull);
	}
	public static String cxxNamespace(String packageName){
		return cxxNamespace(packageName,true);
	}

	public static String cxxNamespace(Class<?>clazz){
		return cxxNamespace(clazz,true);
	}
	public static String cxxClassName(Class<?>clazz,boolean isfull ){
		if(null==clazz){
			return "";
		}
		if(isfull){
			return cxxNamespace(clazz.getPackage().getName() + "." + clazz.getSimpleName(),true) ;
		}
		return clazz.getSimpleName();
	}

	public static String cxxClassName(Class<?>clazz){
		return getTypeName(cxxClassName(clazz,true));
	}
	/**
	 * 返回一个c++类名的简单类名,类似 {@link Class#getSimpleName()}
	 * @param cxxType
	 */
	public static String simpleName(String cxxType){
		if(null != cxxType){
			return cxxType.replaceAll("^(?:::)?(?:\\w+::)*", "");
		}
		return cxxType;
	}
	public static String getCxxNamespace(String cxxType){
		if(null == cxxType){
			return "";
		}
		return cxxType.replaceAll("::\\w+$", "");
	}
	public static String getCxxNamespaceOfJava(String javaClassName){
		if(null == javaClassName){
			return "";
		}
		return getCxxNamespace(cxxNamespace(javaClassName,true));
	}
	/**
	 * 根据当前namespace返回最简单的类型名
	 * @param cxxType cxx类名
	 */
	public static String getTypeName(String cxxType){
		checkArgument((!Strings.isNullOrEmpty(cxxType)) && cxxType.indexOf('.') == -1,
				"invalid c++ Type %s",cxxType);
		String cns = getCurrentNamespace();
		if(!cns.isEmpty()){
			cns = getCurrentNamespace() + "::";
		}
		return cxxType.replaceFirst(cns, "");
	}
	public CxxType getCxxType(Type type){
		return CxxType.getThriftType(type);
	}
	/**
	 * 判断指定的类型是否需要类型转换
	 * @param type
	 */
	public boolean needCast(Type type){
		return CxxType.getThriftType(type).isNeedCast();
	}
}
